home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / zipfile.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  22KB  |  790 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. import struct
  5. import os
  6. import time
  7. import sys
  8. import binascii
  9. import cStringIO
  10.  
  11. try:
  12.     import zlib
  13. except ImportError:
  14.     zlib = None
  15.  
  16. __all__ = [
  17.     'BadZipfile',
  18.     'error',
  19.     'ZIP_STORED',
  20.     'ZIP_DEFLATED',
  21.     'is_zipfile',
  22.     'ZipInfo',
  23.     'ZipFile',
  24.     'PyZipFile',
  25.     'LargeZipFile']
  26.  
  27. class BadZipfile(Exception):
  28.     pass
  29.  
  30.  
  31. class LargeZipFile(Exception):
  32.     pass
  33.  
  34. error = BadZipfile
  35. ZIP64_LIMIT = (1 << 31) - 1
  36. ZIP_STORED = 0
  37. ZIP_DEFLATED = 8
  38. structEndArchive = '<4s4H2LH'
  39. stringEndArchive = 'PK\x05\x06'
  40. structCentralDir = '<4s4B4HlLL5HLL'
  41. stringCentralDir = 'PK\x01\x02'
  42. structFileHeader = '<4s2B4HlLL2H'
  43. stringFileHeader = 'PK\x03\x04'
  44. structEndArchive64Locator = '<4slql'
  45. stringEndArchive64Locator = 'PK\x06\x07'
  46. structEndArchive64 = '<4sqhhllqqqq'
  47. stringEndArchive64 = 'PK\x06\x06'
  48. _CD_SIGNATURE = 0
  49. _CD_CREATE_VERSION = 1
  50. _CD_CREATE_SYSTEM = 2
  51. _CD_EXTRACT_VERSION = 3
  52. _CD_EXTRACT_SYSTEM = 4
  53. _CD_FLAG_BITS = 5
  54. _CD_COMPRESS_TYPE = 6
  55. _CD_TIME = 7
  56. _CD_DATE = 8
  57. _CD_CRC = 9
  58. _CD_COMPRESSED_SIZE = 10
  59. _CD_UNCOMPRESSED_SIZE = 11
  60. _CD_FILENAME_LENGTH = 12
  61. _CD_EXTRA_FIELD_LENGTH = 13
  62. _CD_COMMENT_LENGTH = 14
  63. _CD_DISK_NUMBER_START = 15
  64. _CD_INTERNAL_FILE_ATTRIBUTES = 16
  65. _CD_EXTERNAL_FILE_ATTRIBUTES = 17
  66. _CD_LOCAL_HEADER_OFFSET = 18
  67. _FH_SIGNATURE = 0
  68. _FH_EXTRACT_VERSION = 1
  69. _FH_EXTRACT_SYSTEM = 2
  70. _FH_GENERAL_PURPOSE_FLAG_BITS = 3
  71. _FH_COMPRESSION_METHOD = 4
  72. _FH_LAST_MOD_TIME = 5
  73. _FH_LAST_MOD_DATE = 6
  74. _FH_CRC = 7
  75. _FH_COMPRESSED_SIZE = 8
  76. _FH_UNCOMPRESSED_SIZE = 9
  77. _FH_FILENAME_LENGTH = 10
  78. _FH_EXTRA_FIELD_LENGTH = 11
  79.  
  80. def is_zipfile(filename):
  81.     
  82.     try:
  83.         fpin = open(filename, 'rb')
  84.         endrec = _EndRecData(fpin)
  85.         fpin.close()
  86.         if endrec:
  87.             return True
  88.     except IOError:
  89.         pass
  90.  
  91.     return False
  92.  
  93.  
  94. def _EndRecData64(fpin, offset, endrec):
  95.     locatorSize = struct.calcsize(structEndArchive64Locator)
  96.     fpin.seek(offset - locatorSize, 2)
  97.     data = fpin.read(locatorSize)
  98.     (sig, diskno, reloff, disks) = struct.unpack(structEndArchive64Locator, data)
  99.     if sig != stringEndArchive64Locator:
  100.         return endrec
  101.     
  102.     if diskno != 0 or disks != 1:
  103.         raise BadZipfile('zipfiles that span multiple disks are not supported')
  104.     
  105.     endArchiveSize = struct.calcsize(structEndArchive64)
  106.     fpin.seek(offset - locatorSize - endArchiveSize, 2)
  107.     data = fpin.read(endArchiveSize)
  108.     (sig, sz, create_version, read_version, disk_num, disk_dir, dircount, dircount2, dirsize, diroffset) = struct.unpack(structEndArchive64, data)
  109.     if sig != stringEndArchive64:
  110.         return endrec
  111.     
  112.     endrec[1] = disk_num
  113.     endrec[2] = disk_dir
  114.     endrec[3] = dircount
  115.     endrec[4] = dircount2
  116.     endrec[5] = dirsize
  117.     endrec[6] = diroffset
  118.     return endrec
  119.  
  120.  
  121. def _EndRecData(fpin):
  122.     fpin.seek(-22, 2)
  123.     filesize = fpin.tell() + 22
  124.     data = fpin.read()
  125.     if data[0:4] == stringEndArchive and data[-2:] == '\x00\x00':
  126.         endrec = struct.unpack(structEndArchive, data)
  127.         endrec = list(endrec)
  128.         endrec.append('')
  129.         endrec.append(filesize - 22)
  130.         if endrec[-4] == -1 or endrec[-4] == 0xFFFFFFFFL:
  131.             return _EndRecData64(fpin, -22, endrec)
  132.         
  133.         return endrec
  134.     
  135.     END_BLOCK = min(filesize, 4096)
  136.     fpin.seek(filesize - END_BLOCK, 0)
  137.     data = fpin.read()
  138.     start = data.rfind(stringEndArchive)
  139.     if start >= 0:
  140.         endrec = struct.unpack(structEndArchive, data[start:start + 22])
  141.         endrec = list(endrec)
  142.         comment = data[start + 22:]
  143.         if endrec[7] == len(comment):
  144.             endrec.append(comment)
  145.             endrec.append((filesize - END_BLOCK) + start)
  146.             if endrec[-4] == -1 or endrec[-4] == 0xFFFFFFFFL:
  147.                 return _EndRecData64(fpin, -END_BLOCK + start, endrec)
  148.             
  149.             return endrec
  150.         
  151.     
  152.  
  153.  
  154. class ZipInfo(object):
  155.     __slots__ = ('orig_filename', 'filename', 'date_time', 'compress_type', 'comment', 'extra', 'create_system', 'create_version', 'extract_version', 'reserved', 'flag_bits', 'volume', 'internal_attr', 'external_attr', 'header_offset', 'CRC', 'compress_size', 'file_size')
  156.     
  157.     def __init__(self, filename = 'NoName', date_time = (1980, 1, 1, 0, 0, 0)):
  158.         self.orig_filename = filename
  159.         null_byte = filename.find(chr(0))
  160.         if null_byte >= 0:
  161.             filename = filename[0:null_byte]
  162.         
  163.         if os.sep != '/' and os.sep in filename:
  164.             filename = filename.replace(os.sep, '/')
  165.         
  166.         self.filename = filename
  167.         self.date_time = date_time
  168.         self.compress_type = ZIP_STORED
  169.         self.comment = ''
  170.         self.extra = ''
  171.         if sys.platform == 'win32':
  172.             self.create_system = 0
  173.         else:
  174.             self.create_system = 3
  175.         self.create_version = 20
  176.         self.extract_version = 20
  177.         self.reserved = 0
  178.         self.flag_bits = 0
  179.         self.volume = 0
  180.         self.internal_attr = 0
  181.         self.external_attr = 0
  182.  
  183.     
  184.     def FileHeader(self):
  185.         dt = self.date_time
  186.         dosdate = dt[0] - 1980 << 9 | dt[1] << 5 | dt[2]
  187.         dostime = dt[3] << 11 | dt[4] << 5 | dt[5] // 2
  188.         if self.flag_bits & 8:
  189.             CRC = compress_size = file_size = 0
  190.         else:
  191.             CRC = self.CRC
  192.             compress_size = self.compress_size
  193.             file_size = self.file_size
  194.         extra = self.extra
  195.         if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT:
  196.             fmt = '<hhqq'
  197.             extra = extra + struct.pack(fmt, 1, struct.calcsize(fmt) - 4, file_size, compress_size)
  198.             file_size = 0xFFFFFFFFL
  199.             compress_size = 0xFFFFFFFFL
  200.             self.extract_version = max(45, self.extract_version)
  201.             self.create_version = max(45, self.extract_version)
  202.         
  203.         header = struct.pack(structFileHeader, stringFileHeader, self.extract_version, self.reserved, self.flag_bits, self.compress_type, dostime, dosdate, CRC, compress_size, file_size, len(self.filename), len(extra))
  204.         return header + self.filename + extra
  205.  
  206.     
  207.     def _decodeExtra(self):
  208.         extra = self.extra
  209.         unpack = struct.unpack
  210.         while extra:
  211.             (tp, ln) = unpack('<hh', extra[:4])
  212.             if tp == 1:
  213.                 if ln >= 24:
  214.                     counts = unpack('<qqq', extra[4:28])
  215.                 elif ln == 16:
  216.                     counts = unpack('<qq', extra[4:20])
  217.                 elif ln == 8:
  218.                     counts = unpack('<q', extra[4:12])
  219.                 elif ln == 0:
  220.                     counts = ()
  221.                 else:
  222.                     raise RuntimeError, 'Corrupt extra field %s' % (ln,)
  223.                 idx = 0
  224.                 if self.file_size == -1 or self.file_size == 0xFFFFFFFFL:
  225.                     self.file_size = counts[idx]
  226.                     idx += 1
  227.                 
  228.                 if self.compress_size == -1 or self.compress_size == 0xFFFFFFFFL:
  229.                     self.compress_size = counts[idx]
  230.                     idx += 1
  231.                 
  232.                 if self.header_offset == -1 or self.header_offset == 0xFFFFFFFFL:
  233.                     old = self.header_offset
  234.                     self.header_offset = counts[idx]
  235.                     idx += 1
  236.                 
  237.             
  238.             extra = extra[ln + 4:]
  239.  
  240.  
  241.  
  242. class ZipFile:
  243.     fp = None
  244.     
  245.     def __init__(self, file, mode = 'r', compression = ZIP_STORED, allowZip64 = False):
  246.         self._allowZip64 = allowZip64
  247.         self._didModify = False
  248.         if compression == ZIP_STORED:
  249.             pass
  250.         elif compression == ZIP_DEFLATED:
  251.             if not zlib:
  252.                 raise RuntimeError, 'Compression requires the (missing) zlib module'
  253.             
  254.         else:
  255.             raise RuntimeError, 'That compression method is not supported'
  256.         self.debug = 0
  257.         self.NameToInfo = { }
  258.         self.filelist = []
  259.         self.compression = compression
  260.         self.mode = key = mode.replace('b', '')[0]
  261.         if isinstance(file, basestring):
  262.             self._filePassed = 0
  263.             self.filename = file
  264.             modeDict = {
  265.                 'r': 'rb',
  266.                 'w': 'wb',
  267.                 'a': 'r+b' }
  268.             self.fp = open(file, modeDict[mode])
  269.         else:
  270.             self._filePassed = 1
  271.             self.fp = file
  272.             self.filename = getattr(file, 'name', None)
  273.         if key == 'r':
  274.             self._GetContents()
  275.         elif key == 'w':
  276.             pass
  277.         elif key == 'a':
  278.             
  279.             try:
  280.                 self._RealGetContents()
  281.                 self.fp.seek(self.start_dir, 0)
  282.             except BadZipfile:
  283.                 self.fp.seek(0, 2)
  284.             except:
  285.                 None<EXCEPTION MATCH>BadZipfile
  286.             
  287.  
  288.         None<EXCEPTION MATCH>BadZipfile
  289.         if not self._filePassed:
  290.             self.fp.close()
  291.             self.fp = None
  292.         
  293.         raise RuntimeError, 'Mode must be "r", "w" or "a"'
  294.  
  295.     
  296.     def _GetContents(self):
  297.         
  298.         try:
  299.             self._RealGetContents()
  300.         except BadZipfile:
  301.             if not self._filePassed:
  302.                 self.fp.close()
  303.                 self.fp = None
  304.             
  305.             raise 
  306.  
  307.  
  308.     
  309.     def _RealGetContents(self):
  310.         fp = self.fp
  311.         endrec = _EndRecData(fp)
  312.         if not endrec:
  313.             raise BadZipfile, 'File is not a zip file'
  314.         
  315.         if self.debug > 1:
  316.             print endrec
  317.         
  318.         size_cd = endrec[5]
  319.         offset_cd = endrec[6]
  320.         self.comment = endrec[8]
  321.         if endrec[9] > ZIP64_LIMIT:
  322.             x = endrec[9] - size_cd - 56 - 20
  323.         else:
  324.             x = endrec[9] - size_cd
  325.         concat = x - offset_cd
  326.         if self.debug > 2:
  327.             print 'given, inferred, offset', offset_cd, x, concat
  328.         
  329.         self.start_dir = offset_cd + concat
  330.         fp.seek(self.start_dir, 0)
  331.         data = fp.read(size_cd)
  332.         fp = cStringIO.StringIO(data)
  333.         total = 0
  334.         while total < size_cd:
  335.             centdir = fp.read(46)
  336.             total = total + 46
  337.             if centdir[0:4] != stringCentralDir:
  338.                 raise BadZipfile, 'Bad magic number for central directory'
  339.             
  340.             centdir = struct.unpack(structCentralDir, centdir)
  341.             if self.debug > 2:
  342.                 print centdir
  343.             
  344.             filename = fp.read(centdir[_CD_FILENAME_LENGTH])
  345.             x = ZipInfo(filename)
  346.             x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
  347.             x.comment = fp.read(centdir[_CD_COMMENT_LENGTH])
  348.             total = total + centdir[_CD_FILENAME_LENGTH] + centdir[_CD_EXTRA_FIELD_LENGTH] + centdir[_CD_COMMENT_LENGTH]
  349.             x.header_offset = centdir[_CD_LOCAL_HEADER_OFFSET]
  350.             (x.create_version, x.create_system, x.extract_version, x.reserved, x.flag_bits, x.compress_type, t, d, x.CRC, x.compress_size, x.file_size) = centdir[1:12]
  351.             (x.volume, x.internal_attr, x.external_attr) = centdir[15:18]
  352.             x.date_time = ((d >> 9) + 1980, d >> 5 & 15, d & 31, t >> 11, t >> 5 & 63, (t & 31) * 2)
  353.             x._decodeExtra()
  354.             x.header_offset = x.header_offset + concat
  355.             self.filelist.append(x)
  356.             self.NameToInfo[x.filename] = x
  357.             if self.debug > 2:
  358.                 print 'total', total
  359.                 continue
  360.  
  361.     
  362.     def namelist(self):
  363.         l = []
  364.         for data in self.filelist:
  365.             l.append(data.filename)
  366.         
  367.         return l
  368.  
  369.     
  370.     def infolist(self):
  371.         return self.filelist
  372.  
  373.     
  374.     def printdir(self):
  375.         print '%-46s %19s %12s' % ('File Name', 'Modified    ', 'Size')
  376.         for zinfo in self.filelist:
  377.             date = '%d-%02d-%02d %02d:%02d:%02d' % zinfo.date_time[:6]
  378.             print '%-46s %s %12d' % (zinfo.filename, date, zinfo.file_size)
  379.         
  380.  
  381.     
  382.     def testzip(self):
  383.         for zinfo in self.filelist:
  384.             
  385.             try:
  386.                 self.read(zinfo.filename)
  387.             continue
  388.             except BadZipfile:
  389.                 return zinfo.filename
  390.                 continue
  391.             
  392.  
  393.         
  394.  
  395.     
  396.     def getinfo(self, name):
  397.         return self.NameToInfo[name]
  398.  
  399.     
  400.     def read(self, name):
  401.         if self.mode not in ('r', 'a'):
  402.             raise RuntimeError, 'read() requires mode "r" or "a"'
  403.         
  404.         if not self.fp:
  405.             raise RuntimeError, 'Attempt to read ZIP archive that was already closed'
  406.         
  407.         zinfo = self.getinfo(name)
  408.         filepos = self.fp.tell()
  409.         self.fp.seek(zinfo.header_offset, 0)
  410.         fheader = self.fp.read(30)
  411.         if fheader[0:4] != stringFileHeader:
  412.             raise BadZipfile, 'Bad magic number for file header'
  413.         
  414.         fheader = struct.unpack(structFileHeader, fheader)
  415.         fname = self.fp.read(fheader[_FH_FILENAME_LENGTH])
  416.         if fheader[_FH_EXTRA_FIELD_LENGTH]:
  417.             self.fp.read(fheader[_FH_EXTRA_FIELD_LENGTH])
  418.         
  419.         if fname != zinfo.orig_filename:
  420.             raise BadZipfile, 'File name in directory "%s" and header "%s" differ.' % (zinfo.orig_filename, fname)
  421.         
  422.         bytes = self.fp.read(zinfo.compress_size)
  423.         self.fp.seek(filepos, 0)
  424.         if zinfo.compress_type == ZIP_STORED:
  425.             pass
  426.         elif zinfo.compress_type == ZIP_DEFLATED:
  427.             if not zlib:
  428.                 raise RuntimeError, 'De-compression requires the (missing) zlib module'
  429.             
  430.             dc = zlib.decompressobj(-15)
  431.             bytes = dc.decompress(bytes)
  432.             ex = dc.decompress('Z') + dc.flush()
  433.             if ex:
  434.                 bytes = bytes + ex
  435.             
  436.         else:
  437.             raise BadZipfile, 'Unsupported compression method %d for file %s' % (zinfo.compress_type, name)
  438.         crc = binascii.crc32(bytes)
  439.         if crc != zinfo.CRC:
  440.             raise BadZipfile, 'Bad CRC-32 for file %s' % name
  441.         
  442.         return bytes
  443.  
  444.     
  445.     def _writecheck(self, zinfo):
  446.         if zinfo.filename in self.NameToInfo:
  447.             if self.debug:
  448.                 print 'Duplicate name:', zinfo.filename
  449.             
  450.         
  451.         if self.mode not in ('w', 'a'):
  452.             raise RuntimeError, 'write() requires mode "w" or "a"'
  453.         
  454.         if not self.fp:
  455.             raise RuntimeError, 'Attempt to write ZIP archive that was already closed'
  456.         
  457.         if zinfo.compress_type == ZIP_DEFLATED and not zlib:
  458.             raise RuntimeError, 'Compression requires the (missing) zlib module'
  459.         
  460.         if zinfo.compress_type not in (ZIP_STORED, ZIP_DEFLATED):
  461.             raise RuntimeError, 'That compression method is not supported'
  462.         
  463.         if zinfo.file_size > ZIP64_LIMIT:
  464.             if not self._allowZip64:
  465.                 raise LargeZipFile('Filesize would require ZIP64 extensions')
  466.             
  467.         
  468.         if zinfo.header_offset > ZIP64_LIMIT:
  469.             if not self._allowZip64:
  470.                 raise LargeZipFile('Zipfile size would require ZIP64 extensions')
  471.             
  472.         
  473.  
  474.     
  475.     def write(self, filename, arcname = None, compress_type = None):
  476.         st = os.stat(filename)
  477.         mtime = time.localtime(st.st_mtime)
  478.         date_time = mtime[0:6]
  479.         if arcname is None:
  480.             arcname = filename
  481.         
  482.         arcname = os.path.normpath(os.path.splitdrive(arcname)[1])
  483.         while arcname[0] in (os.sep, os.altsep):
  484.             arcname = arcname[1:]
  485.         zinfo = ZipInfo(arcname, date_time)
  486.         zinfo.external_attr = (st[0] & 65535) << 0x10L
  487.         if compress_type is None:
  488.             zinfo.compress_type = self.compression
  489.         else:
  490.             zinfo.compress_type = compress_type
  491.         zinfo.file_size = st.st_size
  492.         zinfo.flag_bits = 0
  493.         zinfo.header_offset = self.fp.tell()
  494.         self._writecheck(zinfo)
  495.         self._didModify = True
  496.         fp = open(filename, 'rb')
  497.         zinfo.CRC = CRC = 0
  498.         zinfo.compress_size = compress_size = 0
  499.         zinfo.file_size = file_size = 0
  500.         self.fp.write(zinfo.FileHeader())
  501.         if zinfo.compress_type == ZIP_DEFLATED:
  502.             cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
  503.         else:
  504.             cmpr = None
  505.         while None:
  506.             buf = fp.read(8192)
  507.             if not buf:
  508.                 break
  509.             
  510.             file_size = file_size + len(buf)
  511.             CRC = binascii.crc32(buf, CRC)
  512.             if cmpr:
  513.                 buf = cmpr.compress(buf)
  514.                 compress_size = compress_size + len(buf)
  515.             
  516.             continue
  517.             fp.close()
  518.             if cmpr:
  519.                 buf = cmpr.flush()
  520.                 compress_size = compress_size + len(buf)
  521.                 self.fp.write(buf)
  522.                 zinfo.compress_size = compress_size
  523.             else:
  524.                 zinfo.compress_size = file_size
  525.         zinfo.CRC = CRC
  526.         zinfo.file_size = file_size
  527.         position = self.fp.tell()
  528.         self.fp.seek(zinfo.header_offset + 14, 0)
  529.         self.fp.write(struct.pack('<lLL', zinfo.CRC, zinfo.compress_size, zinfo.file_size))
  530.         self.fp.seek(position, 0)
  531.         self.filelist.append(zinfo)
  532.         self.NameToInfo[zinfo.filename] = zinfo
  533.  
  534.     
  535.     def writestr(self, zinfo_or_arcname, bytes):
  536.         if not isinstance(zinfo_or_arcname, ZipInfo):
  537.             zinfo = ZipInfo(filename = zinfo_or_arcname, date_time = time.localtime(time.time())[:6])
  538.             zinfo.compress_type = self.compression
  539.         else:
  540.             zinfo = zinfo_or_arcname
  541.         zinfo.file_size = len(bytes)
  542.         zinfo.header_offset = self.fp.tell()
  543.         self._writecheck(zinfo)
  544.         self._didModify = True
  545.         zinfo.CRC = binascii.crc32(bytes)
  546.         if zinfo.compress_type == ZIP_DEFLATED:
  547.             co = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
  548.             bytes = co.compress(bytes) + co.flush()
  549.             zinfo.compress_size = len(bytes)
  550.         else:
  551.             zinfo.compress_size = zinfo.file_size
  552.         zinfo.header_offset = self.fp.tell()
  553.         self.fp.write(zinfo.FileHeader())
  554.         self.fp.write(bytes)
  555.         self.fp.flush()
  556.         if zinfo.flag_bits & 8:
  557.             self.fp.write(struct.pack('<lLL', zinfo.CRC, zinfo.compress_size, zinfo.file_size))
  558.         
  559.         self.filelist.append(zinfo)
  560.         self.NameToInfo[zinfo.filename] = zinfo
  561.  
  562.     
  563.     def __del__(self):
  564.         self.close()
  565.  
  566.     
  567.     def close(self):
  568.         if self.fp is None:
  569.             return None
  570.         
  571.         if self.mode in ('w', 'a') and self._didModify:
  572.             count = 0
  573.             pos1 = self.fp.tell()
  574.             for zinfo in self.filelist:
  575.                 count = count + 1
  576.                 dt = zinfo.date_time
  577.                 dosdate = dt[0] - 1980 << 9 | dt[1] << 5 | dt[2]
  578.                 dostime = dt[3] << 11 | dt[4] << 5 | dt[5] // 2
  579.                 extra = []
  580.                 if zinfo.file_size > ZIP64_LIMIT or zinfo.compress_size > ZIP64_LIMIT:
  581.                     extra.append(zinfo.file_size)
  582.                     extra.append(zinfo.compress_size)
  583.                     file_size = 0xFFFFFFFFL
  584.                     compress_size = 0xFFFFFFFFL
  585.                 else:
  586.                     file_size = zinfo.file_size
  587.                     compress_size = zinfo.compress_size
  588.                 if zinfo.header_offset > ZIP64_LIMIT:
  589.                     extra.append(zinfo.header_offset)
  590.                     header_offset = -1
  591.                 else:
  592.                     header_offset = zinfo.header_offset
  593.                 extra_data = zinfo.extra
  594.                 if extra:
  595.                     extra_data = struct.pack('<hh' + 'q' * len(extra), 1, 8 * len(extra), *extra) + extra_data
  596.                     extract_version = max(45, zinfo.extract_version)
  597.                     create_version = max(45, zinfo.create_version)
  598.                 else:
  599.                     extract_version = zinfo.extract_version
  600.                     create_version = zinfo.create_version
  601.                 centdir = struct.pack(structCentralDir, stringCentralDir, create_version, zinfo.create_system, extract_version, zinfo.reserved, zinfo.flag_bits, zinfo.compress_type, dostime, dosdate, zinfo.CRC, compress_size, file_size, len(zinfo.filename), len(extra_data), len(zinfo.comment), 0, zinfo.internal_attr, zinfo.external_attr, header_offset)
  602.                 self.fp.write(centdir)
  603.                 self.fp.write(zinfo.filename)
  604.                 self.fp.write(extra_data)
  605.                 self.fp.write(zinfo.comment)
  606.             
  607.             pos2 = self.fp.tell()
  608.             if pos1 > ZIP64_LIMIT:
  609.                 zip64endrec = struct.pack(structEndArchive64, stringEndArchive64, 44, 45, 45, 0, 0, count, count, pos2 - pos1, pos1)
  610.                 self.fp.write(zip64endrec)
  611.                 zip64locrec = struct.pack(structEndArchive64Locator, stringEndArchive64Locator, 0, pos2, 1)
  612.                 self.fp.write(zip64locrec)
  613.                 pos3 = self.fp.tell()
  614.                 endrec = struct.pack(structEndArchive, stringEndArchive, 0, 0, count, count, pos2 - pos1, -1, 0)
  615.                 self.fp.write(endrec)
  616.             else:
  617.                 endrec = struct.pack(structEndArchive, stringEndArchive, 0, 0, count, count, pos2 - pos1, pos1, 0)
  618.                 self.fp.write(endrec)
  619.             self.fp.flush()
  620.         
  621.         if not self._filePassed:
  622.             self.fp.close()
  623.         
  624.         self.fp = None
  625.  
  626.  
  627.  
  628. class PyZipFile(ZipFile):
  629.     
  630.     def writepy(self, pathname, basename = ''):
  631.         (dir, name) = os.path.split(pathname)
  632.         if os.path.isdir(pathname):
  633.             initname = os.path.join(pathname, '__init__.py')
  634.             if os.path.isfile(initname):
  635.                 if basename:
  636.                     basename = '%s/%s' % (basename, name)
  637.                 else:
  638.                     basename = name
  639.                 if self.debug:
  640.                     print 'Adding package in', pathname, 'as', basename
  641.                 
  642.                 (fname, arcname) = self._get_codename(initname[0:-3], basename)
  643.                 if self.debug:
  644.                     print 'Adding', arcname
  645.                 
  646.                 self.write(fname, arcname)
  647.                 dirlist = os.listdir(pathname)
  648.                 dirlist.remove('__init__.py')
  649.                 for filename in dirlist:
  650.                     path = os.path.join(pathname, filename)
  651.                     (root, ext) = os.path.splitext(filename)
  652.                     if os.path.isdir(path):
  653.                         if os.path.isfile(os.path.join(path, '__init__.py')):
  654.                             self.writepy(path, basename)
  655.                         
  656.                     os.path.isfile(os.path.join(path, '__init__.py'))
  657.                     if ext == '.py':
  658.                         (fname, arcname) = self._get_codename(path[0:-3], basename)
  659.                         if self.debug:
  660.                             print 'Adding', arcname
  661.                         
  662.                         self.write(fname, arcname)
  663.                         continue
  664.                 
  665.             elif self.debug:
  666.                 print 'Adding files from directory', pathname
  667.             
  668.             for filename in os.listdir(pathname):
  669.                 path = os.path.join(pathname, filename)
  670.                 (root, ext) = os.path.splitext(filename)
  671.                 if ext == '.py':
  672.                     (fname, arcname) = self._get_codename(path[0:-3], basename)
  673.                     if self.debug:
  674.                         print 'Adding', arcname
  675.                     
  676.                     self.write(fname, arcname)
  677.                     continue
  678.             
  679.         elif pathname[-3:] != '.py':
  680.             raise RuntimeError, 'Files added with writepy() must end with ".py"'
  681.         
  682.         (fname, arcname) = self._get_codename(pathname[0:-3], basename)
  683.         if self.debug:
  684.             print 'Adding file', arcname
  685.         
  686.         self.write(fname, arcname)
  687.  
  688.     
  689.     def _get_codename(self, pathname, basename):
  690.         file_py = pathname + '.py'
  691.         file_pyc = pathname + '.pyc'
  692.         file_pyo = pathname + '.pyo'
  693.         if os.path.isfile(file_pyo) and os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime:
  694.             fname = file_pyo
  695.         elif not os.path.isfile(file_pyc) or os.stat(file_pyc).st_mtime < os.stat(file_py).st_mtime:
  696.             import py_compile as py_compile
  697.             if self.debug:
  698.                 print 'Compiling', file_py
  699.             
  700.             
  701.             try:
  702.                 py_compile.compile(file_py, file_pyc, None, True)
  703.             except py_compile.PyCompileError:
  704.                 err = None
  705.                 print err.msg
  706.  
  707.             fname = file_pyc
  708.         else:
  709.             fname = file_pyc
  710.         archivename = os.path.split(fname)[1]
  711.         if basename:
  712.             archivename = '%s/%s' % (basename, archivename)
  713.         
  714.         return (fname, archivename)
  715.  
  716.  
  717.  
  718. def main(args = None):
  719.     import textwrap as textwrap
  720.     USAGE = textwrap.dedent('        Usage:\n            zipfile.py -l zipfile.zip        # Show listing of a zipfile\n            zipfile.py -t zipfile.zip        # Test if a zipfile is valid\n            zipfile.py -e zipfile.zip target # Extract zipfile into target dir\n            zipfile.py -c zipfile.zip src ... # Create zipfile from sources\n        ')
  721.     if args is None:
  722.         args = sys.argv[1:]
  723.     
  724.     if not args or args[0] not in ('-l', '-c', '-e', '-t'):
  725.         print USAGE
  726.         sys.exit(1)
  727.     
  728.     if args[0] == '-l':
  729.         if len(args) != 2:
  730.             print USAGE
  731.             sys.exit(1)
  732.         
  733.         zf = ZipFile(args[1], 'r')
  734.         zf.printdir()
  735.         zf.close()
  736.     elif args[0] == '-t':
  737.         if len(args) != 2:
  738.             print USAGE
  739.             sys.exit(1)
  740.         
  741.         zf = ZipFile(args[1], 'r')
  742.         zf.testzip()
  743.         print 'Done testing'
  744.     elif args[0] == '-e':
  745.         if len(args) != 3:
  746.             print USAGE
  747.             sys.exit(1)
  748.         
  749.         zf = ZipFile(args[1], 'r')
  750.         out = args[2]
  751.         for path in zf.namelist():
  752.             if path.startswith('./'):
  753.                 tgt = os.path.join(out, path[2:])
  754.             else:
  755.                 tgt = os.path.join(out, path)
  756.             tgtdir = os.path.dirname(tgt)
  757.             if not os.path.exists(tgtdir):
  758.                 os.makedirs(tgtdir)
  759.             
  760.             fp = open(tgt, 'wb')
  761.             fp.write(zf.read(path))
  762.             fp.close()
  763.         
  764.         zf.close()
  765.     elif args[0] == '-c':
  766.         if len(args) < 3:
  767.             print USAGE
  768.             sys.exit(1)
  769.         
  770.         
  771.         def addToZip(zf, path, zippath):
  772.             if os.path.isfile(path):
  773.                 zf.write(path, zippath, ZIP_DEFLATED)
  774.             elif os.path.isdir(path):
  775.                 for nm in os.listdir(path):
  776.                     addToZip(zf, os.path.join(path, nm), os.path.join(zippath, nm))
  777.                 
  778.             
  779.  
  780.         zf = ZipFile(args[1], 'w', allowZip64 = True)
  781.         for src in args[2:]:
  782.             addToZip(zf, src, os.path.basename(src))
  783.         
  784.         zf.close()
  785.     
  786.  
  787. if __name__ == '__main__':
  788.     main()
  789.  
  790.